/*
 *  Copyright 2009 Honiewelle Flores 
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License"); 
 *  you may not use this file except in compliance with the License. 
 *  You may obtain a copy of the License at 
 *  
 *  	http://www.apache.org/licenses/LICENSE-2.0 
 *  
 *  Unless required by applicable law or agreed to in writing, software 
 *  distributed under the License is distributed on an "AS IS" BASIS, 
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 *  See the License for the specific language governing permissions and 
 *  limitations under the License. 
 */

package com.einox.chikko;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class Packet {

	private static int currentPacketNumber = 1;
	
	private int packetNumber;
	private int operationCode;
	private int checksum;
	private Map<Integer,String> parameters;
	
	
	
	public Packet(){
		this(currentPacketNumber);
		currentPacketNumber += 2;
		if (currentPacketNumber > 255){
			currentPacketNumber = 0;
		}	
	}
	
	public Packet(int packetNumber){
		this.packetNumber = packetNumber;
		parameters = new LinkedHashMap<Integer, String>();
	}
	
	
	
	public Packet(String rawMessage) throws InvalidChikkoPacketException{
		String [] vMessage = rawMessage.split("\t");
		String [] header = vMessage[0].split(":");
		String [] parameter = Arrays.copyOfRange(vMessage, 1, vMessage.length-1);
		String checksum = vMessage[vMessage.length-1];
		
		// HEADER
		operationCode = Integer.parseInt(header[0]);
		packetNumber = Integer.parseInt(header[1]);
		
		// PARAMETERS
		
		parameters = new LinkedHashMap<Integer, String>();
		for (String i : parameter){
			String [] vi = i.split(":");
			
			parameters.put(Integer.parseInt(vi[0]), vi.length > 1 ? vi[1] : "");
		}
		
		// CHECKSUM
		if (!checksum.equals(computeChecksum(compile()))){
			throw new InvalidChikkoPacketException("Checksum error.");
		}
		
		this.checksum = Integer.parseInt(checksum, 16);
		
		
	}
	
	public void addParameter(int code, String value){
		parameters.put(code,value);

	}
	
	public String getParameter(int code){
		return parameters.get(code);
	}
	
	public String toString(){
		StringBuilder result = new StringBuilder();
		
		result.append(compile());
		result.append(computeChecksum(result.toString()));
		result.append("\u0003");
		
		return result.toString();
	}
	
	public int getOperationCode() {
		return operationCode;
	}
	
	public void setOperationCode(int operationCode) {
		this.operationCode = operationCode;
	}
	
	public void setChecksum(int checksum) {
		this.checksum = checksum;
	}
	
	public int getChecksum() {
		return checksum;
	}
	
	/*
	 *  PRIVATE METHODS
	 */
	
	/**
	 * 
	 *  Combines the HEADER and PARAMETER(S)
	 */
	private String compile(){
		
		StringBuilder result = new StringBuilder();
		
		result.append("\u0002");
		result.append(String.format("%02d", operationCode));
		result.append(":");
		result.append(String.format("%03d", packetNumber));
		result.append("\t");
		
		for (int key : parameters.keySet()){
			result.append(String.format("%03d", key));
			result.append(":");
			result.append(parameters.get(key));
			result.append("\t");
		}
				
		return result.toString();
	}
	
	private String computeChecksum(String message){
		int checksum = 0;
		byte [] buffer = message.getBytes();
		
		for (int ctr = 0; ctr < buffer.length; ctr++){
			checksum += buffer[ctr];
			checksum &= 0xff;
		}
		
		return String.format("%02X", checksum);
	}

	public int getPacketNumber() {
		return packetNumber;
	}

}
